<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" :
 * <thepixeldeveloper@googlemail.com> wrote this file. As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return Mathew Davies
 * ----------------------------------------------------------------------------
 */
 
/**
* redux_auth_model
*/
class Users_Model extends Model
{
	/**
	 * Holds an array of tables used in
	 * redux.
	 *
	 * @var string
	 **/
	public $tables = array();
	
	/**
	 * activation code
	 *
	 * @var string
	 **/
	public $activation_code;
	
	/**
	 * forgotten password key
	 *
	 * @var string
	 **/
	public $forgotten_password_code;
	
	/**
	 * new password
	 *
	 * @var string
	 **/
	public $new_password;
	
	/**
	 * Identity
	 *
	 * @var string
	 **/
	public $identity;
	
	public function __construct()
	{
		parent::__construct();
		$this->load->config('redux_auth');
		$this->tables  = $this->config->item('tables');
		$this->columns = $this->config->item('columns');
	}
	
	/**
	 * Misc functions
	 * 
	 * Hash password : Hashes the password to be stored in the database.
     * Hash password db : This function takes a password and validates it
     * against an entry in the users table.
     * Salt : Generates a random salt value.
	 *
	 * @author Mathew
	 */
	 
	/**
	 * Hashes the password to be stored in the database.
	 *
	 * @return void
	 * @author Mathew
	 **/
	public function hash_password($password = false)
	{
	    $salt_length = $this->config->item('salt_length');
	    
	    if ($password === false)
	    {
	        return false;
	    }
	    
		$salt = $this->salt();
		
		$password = $salt . substr(sha1($salt . $password), 0, -$salt_length);
		
		return $password;		
	}
	
	/**
	 * This function takes a password and validates it
     * against an entry in the users table.
	 *
	 * @return void
	 * @author Mathew
	 **/
	public function hash_password_db($identity = false, $password = false)
	{
	    $identity_column   = $this->config->item('identity');
	    $users_table       = $this->tables['users'];
	    $salt_length       = $this->config->item('salt_length');
	    
	    if ($identity === false || $password === false)
	    {
	        return false;
	    }
	    
	    $query  = $this->db->select('password')
                    	   ->where($identity_column, $identity)
                    	   ->limit(1)
                    	   ->get($users_table);
            
        $result = $query->row();
        
		if ($query->num_rows() !== 1)
		{
		    return false;
	    }
	    
		$salt = substr($result->password, 0, $salt_length);

		$password = $salt . substr(sha1($salt . $password), 0, -$salt_length);
        
		return $password;
	}
	
	/**
	 * Generates a random salt value.
	 *
	 * @return void
	 * @author Mathew
	 **/
	public function salt()
	{
		return substr(md5(uniqid(rand(), true)), 0, $this->config->item('salt_length'));
	}
    
	/**
	 * Activation functions
	 * 
     * Activate : Validates and removes activation code.
     * Deactivae : Updates a users row with an activation code.
	 *
	 * @author Mathew
	 */
	
	/**
	 * activate
	 *
	 * @return void
	 * @author Mathew
	 **/
	public function activate($code = false)
	{
	    $identity_column = $this->config->item('identity');
	    $users_table     = $this->tables['users'];
	    
	    if ($code === false)
	    {
	        return false;
	    }
	  
	    $query = $this->db->select($identity_column)
                	      ->where('activation_code', $code)
                	      ->limit(1)
                	      ->get($users_table);
                	      
		$result = $query->row();
        
		if ($query->num_rows() !== 1)
		{
		    return false;
		}
	    
		$identity = $result->{$identity_column};
		
		$data = array('activation_code' => '');
        
		$this->db->update($users_table, $data, array($identity_column => $identity));
		
		return ($this->db->affected_rows() == 1) ? true : false;
	}
	
	/**
	 * Deactivate
	 *
	 * @return void
	 * @author Mathew
	 **/
	public function deactivate($username = false)
	{
	    $users_table = $this->tables['users'];
	    
	    if ($username === false)
	    {
	        return false;
	    }
	    
		$activation_code = sha1(md5(microtime()));
		$this->activation_code = $activation_code;
		
		$data = array('activation_code' => $activation_code);
        
		$this->db->update($users_table, $data, array('username' => $username));
		
		return ($this->db->affected_rows() == 1) ? true : false;
	}

	/**
	 * change password
	 *
	 * @return void
	 * @author Mathew
	 **/
	public function change_password($identity = false, $new = false)
	{
	    $identity_column   = $this->config->item('identity');
	    $users_table       = $this->tables['users'];
	    
	    if ($identity === false || $new === false)
	    {
	        return false;
	    }
	    
	    $query  = $this->db->select('password')
                    	   ->where($identity_column, $identity)
                    	   ->limit(1)
                    	   ->get($users_table);
                    	   
	    $result = $query->row();

	    $db_password = $result->password; 
	    //$old         = $this->hash_password_db($identity, $old);
	    $new         = $this->hash_password($new);

	        $data = array('password' => $new);
	        
	        $this->db->update($users_table, $data, array($identity_column => $identity));
	        
	        return ($this->db->affected_rows() == 1) ? true : false;
	    
	}
	
	/**
	 * Checks username.
	 *
	 * @return void
	 * @author Mathew
	 **/
	public function username_check($username = false)
	{
	    $users_table = $this->tables['users'];
	    
	    if ($username === false)
	    {
	        return false;
	    }
	    
	    $query = $this->db->select('id')
                           ->where('username', $username)
                           ->limit(1)
                           ->get($users_table);
		
		if ($query->num_rows() == 1)
		{
			return true;
		}
		
		return false;
	}
	
	/**
	 * Checks email.
	 *
	 * @return void
	 * @author Mathew
	 **/
	public function email_check($email = false)
	{
	    $users_table = $this->tables['users'];
	    
	    if ($email === false)
	    {
	        return false;
	    }
	    
	    $query = $this->db->select('id')
                           ->where('email', $email)
                           ->limit(1)
                           ->get($users_table);
		
		if ($query->num_rows() == 1)
		{
			return true;
		}
		
		return false;
	}
	
	/**
	 * Identity check
	 *
	 * @return void
	 * @author Mathew
	 **/
	protected function identity_check($identity = false)
	{
	    $identity_column = $this->config->item('identity');
	    $users_table     = $this->tables['users'];
	    
	    if ($identity === false)
	    {
	        return false;
	    }
	    
	    $query = $this->db->select('id')
                           ->where($identity_column, $identity)
                           ->limit(1)
                           ->get($users_table);
		
		if ($query->num_rows() == 1)
		{
			return true;
		}
		
		return false;
	}

	/**
	 * Insert a forgotten password key.
	 *
	 * @return void
	 * @author Mathew
	 **/
	public function forgotten_password($email = false)
	{
	    $users_table = $this->tables['users'];
	    
	    if ($email === false)
	    {
	        return false;
	    }
	    
	    $query = $this->db->select('forgotten_password_code')
                    	   ->where('email', $email)
                    	   ->limit(1)
                    	   ->get($users_table);
            
        $result = $query->row();
		
		$code = $result->forgotten_password_code;

		if (empty($code))
		{
			$key = $this->hash_password(microtime().$email);
			
			$this->forgotten_password_code = $key;
		
			$data = array('forgotten_password_code' => $key);
			
			$this->db->update($users_table, $data, array('email' => $email));
			
			return ($this->db->affected_rows() == 1) ? true : false;
		}
		else
		{
			return false;
		}
	}
	
	/**
	 * undocumented function
	 *
	 * @return void
	 * @author Mathew
	 **/
	public function forgotten_password_complete($code = false)
	{
	    $users_table = $this->tables['users'];
	    $identity_column = $this->config->item('identity'); 
	    
	    if ($code === false)
	    {
	        return false;
	    }
	    
	    $query = $this->db->select('id')
                    	   ->where('forgotten_password_code', $code)
                           ->limit(1)
                    	   ->get($users_table);
        
        $result = $query->row();
        
        if ($query->num_rows() > 0)
        {
            $salt       = $this->salt();
		    $password   = $this->hash_password($salt);
		    
		    $this->new_password = $salt;
		    
            $data = array('password'                => $password,
                          'forgotten_password_code' => '0');
            
            $this->db->update($users_table, $data, array('forgotten_password_code' => $code));

            return true;
        }
        
        return false;
	}

	/**
	 * profile
	 *
	 * @return void
	 * @author Mathew
	 **/
	public function profile($identity = false)
	{
	    $users_table     = $this->tables['users'];
	    $groups_table    = $this->tables['groups'];
	    $meta_table      = $this->tables['meta'];
	    $meta_join       = $this->config->item('join');
	    $identity_column = $this->config->item('identity');    
	    
	    if ($identity === false)
	    {
	        return false;
	    }
	    
		$this->db->select($users_table.'.id, '.
						  $users_table.'.username, ' .
						  //$users_table.'.password, '.
						  $users_table.'.email, '.
						  //$users_table.'.activation_code, '.
						  //$users_table.'.forgotten_password_code , '.
						  //$users_table.'.ip_address, '.
						  $groups_table.'.name AS `group`, '.
						  $groups_table.'.id AS `group_id`');
		
		if (!empty($this->columns))
		{
		    foreach ($this->columns as $value)
    		{
    			$this->db->select($meta_table.'.'.$value);
    		}
		}
		
		$this->db->from($users_table);
		$this->db->join($meta_table, $users_table.'.id = '.$meta_table.'.'.$meta_join, 'left');
		$this->db->join($groups_table, $users_table.'.group_id = '.$groups_table.'.id', 'left');
		
		if (strlen($identity) === 40)
	    {
	        $this->db->where($users_table.'.forgotten_password_code', $identity);
	    }
	    else
	    {
	        $this->db->where($users_table.'.'.$identity_column, $identity);
	    }
	    
		$this->db->limit(1);
		$i = $this->db->get();
		
		return ($i->num_rows > 0) ? $i->row() : false;
	}

	/**
	 * Basic functionality
	 * 
	 * Register
	 * Login
	 *
	 * @author Mathew
	 */
	
	/**
	 * register
	 *
	 * @return void
	 * @author Mathew
	 **/
	public function register($username = false, $password = false, $email = false, $additional_data = NULL)
	{
	    $users_table        = $this->tables['users'];
	    $meta_table         = $this->tables['meta'];
	    $groups_table       = $this->tables['groups'];
	    $meta_join          = $this->config->item('join');
	    $additional_columns = $this->config->item('columns');
	    
	    if ($username === false || $password === false || $email === false)
	    {
	        return false;
	    }
	    
        // Group ID
	    $query    = $this->db->select('id')->where('name', $this->config->item('default_group'))->get($groups_table);
	    $result   = $query->row();
	    $group_id = $result->id;
	    
        // IP Address
        $ip_address = $this->input->ip_address();
	    
		$password = $this->hash_password($password);
		
        // Users table.
		$data = array('username' => $username, 
					  'password' => $password, 
					  'email'    => $email,
					  'group_id' => $group_id,
					  'ip_address' => $ip_address);
		  
		$this->db->insert($users_table, $data);
        
		// Meta table.
		$id = $this->db->insert_id();
		
		$data = array($meta_join => $id);
		
		if (!empty($additional_columns))
	    {
	        foreach ($additional_columns as $input)
	        {
	            //$data[$input] = $this->input->post($input);
	            $data[$input] = $additional_data[$input];
	        }
	    }
        
		$this->db->insert($meta_table, $data);
		
		return ($this->db->affected_rows() > 0) ? true : false;
	}
	
	
	/**
	 * login
	 *
	 * @return void
	 * @author Mathew
	 **/
	public function login($identity = false, $password = false)
	{
	    $identity_column = $this->config->item('identity');
	    $users_table     = $this->tables['users'];
	    
	    if ($identity === false || $password === false || $this->identity_check($identity) == false)
	    {
	        return false;
	    }
	    
	    $query = $this->db->select($identity_column.', password, activation_code')
                    	   ->where($identity_column, $identity)
                    	   ->limit(1)
                    	   ->get($users_table);
	    
        $result = $query->row();
        
        if ($query->num_rows() == 1)
        {
            $password = $this->hash_password_db($identity, $password);
            
            if (!empty($result->activation_code)) { return false; }
            
    		if ($result->password === $password)
    		{
    		    $this->session->set_userdata($identity_column,  $result->{$identity_column});
    		    return true;
    		}
        }
        
		return false;		
	}
	
	
	
	/** Añadidas SMORETE **/
	
	//TODO Probar
	public function update($field_data = array()){
		$users_table = $this->tables['users'];
		
		if(isset($field_data['id'])){
			$user = $this->getUserById($field_data['id']);
			
			if($user != NULL){
				$defaults = array(
					'username'		=> $user->username,
					'email'			=> $user->email,
					'group_id'		=> $user->group_id
				);
				
				$field_data = array_merge($defaults, $field_data);
				
				$data = array (
					'username'		=> $field_data['username'],
					'email'			=> $field_data['email'],
					'group_id'		=> $field_data['group_id'],
				);
				
				// Si tiene password, tendremos que pasarle el hash
				if(isset($field_data['password'])){
					$data['password'] = $this->hash_password($field_data['password']);
				}
				
				
				$this->db->where('id', $field_data['id']);
				$this->db->update($users_table, $data);
										
				return ($this->db->affected_rows() > 0) ? TRUE : FALSE;
			
			}
		}
	}
	
	//@TODO Probar
	public function change_user_group($identity = false, $group = NULL){
		
		if($group != NULL)
		{
			$identity_column   	= $this->config->item('identity');
		    $users_table       	= $this->tables['users'];
		    
			if ($identity === false)
		    {
		        return false;
		    }
		    
		    $query = $this->db->select('id')
	                    	   ->where($identity_column, $identity)
	                           ->limit(1)
	                    	   ->get($users_table);
	        
	        $result = $query->row();
	        
	        if ($query->num_rows() > 0)
	        {
			    
	            $data = array('group_id' => $group);
	            
	            $this->db->update($users_table, $data, array($identity_column => $identity));
	
	            return true;
	        }
		}
        
        return false;
	}
	
	//@TODO Probar cambiar info de usuario
	public function change_user_info($identity = false, $additional_data = NULL){
		$identity_column   	= $this->config->item('identity');
	    $users_table       	= $this->tables['users'];
	    $meta_table      	= $this->tables['meta'];
	    $meta_join       	= $this->config->item('join');
	    $additional_columns = $this->config->item('columns');
	    
	    if ($identity === false)
	    {
	        return false;
	    }
	    
	    $query  = $this->db->select('id')
                    	   ->where($identity_column, $identity)
                    	   ->limit(1)
                    	   ->get($users_table);
                    	   	    
		
	    if ($query->num_rows() > 0)
        {
        	$user_id = $query->row()->id;
        	
		    $data = array($meta_join => $user_id);
			
			if (!empty($additional_columns))
		    {
		        foreach ($additional_columns as $field)
		        {
		            $data[$field] = $additional_data[$field];
		        }
		    }
	        
		    // Comprobaremos si existe registro para actualizarlo o crear uno nuevo
		    $query_meta = $this->db->select($meta_join)
		    					   ->where($meta_join, $user_id)
		    					   ->limit(1)
		    					   ->get($meta_table);
			
		    if($query_meta->num_rows() > 0)
		    {
		    	$this->db->update($meta_table, $data, array($meta_join => $user_id));
		    } else
		    {
		    	$this->db->insert($meta_table, $data);
		    }
		    
			
			return ($this->db->affected_rows() > 0) ? true : false;
	    
        }
        
        return FALSE;
	}
	
	/*
	 * Obtiene todos los usuarios del portal
	 */
	public function getAll($config = array()){
		
		$config = $this->_getAllConfig($config);		
		
		$DB = $this->_getAll($config);
		$DB->order_by ( $config['order'] . " " . $config['order_direction'] );

		if ($config['start'] != - 1 && $config['offset'] != - 1) {
			$DB->limit ( $config['offset'], $config['start'] );
		}
		
		$query = $DB->get ();
		
		return $query->result ();
	}
	
	public function getAllCount($config = array()){
		
		$config = $this->_getAllConfig($config);
		
		$DB = $this->_getAll($config);

		return $DB->count_all_results ();
	}
	
	public function _getAllConfig($config = array()){
		return array_merge(array(
			"order"				=> "id",
			"order_direction"	=> "asc",		
			"start"				=> -1,
			"offset"			=> -1,
			"group"				=> -1,
			"group_name"		=> NULL,
			"username"			=> NULL,		
			"email"				=> NULL,
			"query_search"		=> NULL,
			"active"			=> 1 //-1, 0, 1
			
		), $config);
	}
	
	public function _getAll($config = array()){
		
		$users_table        = $this->tables['users'];
	    $meta_table         = $this->tables['meta'];
	    $groups_table       = $this->tables['groups'];
	    $meta_join          = $this->config->item('join');	    
	    
		$this->db->select($users_table.'.id, '.
						  $users_table.'.username, ' .
						  //$users_table.'.password, '.
						  $users_table.'.email, '.
						  //$users_table.'.activation_code, '.
						  //$users_table.'.forgotten_password_code , '.
						  //$users_table.'.ip_address, '.
						  $groups_table.'.name AS `group`, '
						  //$groups_table.'.id AS `group_id`'
						  );
		
		if (!empty($this->columns))
		{
		    foreach ($this->columns as $value)
    		{
    			$this->db->select($meta_table.'.'.$value);
    		}
		}
		
		$this->db->from($users_table);
		$this->db->join($meta_table, $users_table.'.id = '.$meta_table.'.'.$meta_join, 'left');
		$this->db->join($groups_table, $users_table.'.group_id = '.$groups_table.'.id', 'left');
		
		
		if($config['group'] != -1){
			//$where_query = "$groups_table.id = " . $config['group'];
			$this->db->where($groups_table.'.id', $config['group']);
		} else if($config['group_name'] != NULL){
			//$where_query = "$groups_table.name = " . $config['group'];
			$this->db->where($groups_table.'.name', $config['group_name']);
		}
		
		if($config['username']){
			$this->db->like($users_table.'.username', $config['username']);
		}
		
		if($config['email']){
			$this->db->like($users_table.'.email', $config['email']);
		}
		
		if($config['query_search']){
			$where_query = "( $users_table.username LIKE '%".$config['query_search']."%'";
			$where_query .= " OR $users_table.email LIKE '%".$config['query_search']."%'";
			
			if (!empty($this->columns))
			{
			    foreach ($this->columns as $value)
	    		{
	    			$where_query .= " OR $meta_table.$value LIKE '%".$config['query_search']."%'";
	    		}
			}
			$where_query .= ")";
			$this->db->where($where_query);
		}
		
		if($config['active'] == 0){
			$this->db->where($users_table.'.activation_code !=', 0);
		} else if($config['active'] == 1){
			$this->db->where($users_table.'.activation_code', 0);
		}

		return $this->db;
	}
	
	public function getUserById($id){
		$identity_column = $this->config->item('identity');
	    $users_table     = $this->tables['users'];
	    
		$this->db->select($identity_column);
		$this->db->where('id', $id);
		$query = $this->db->get($users_table);
		
		$result = $query->row();
		
		if ($query->num_rows() == 1)
        {
        	return $this->profile($result->{$identity_column});
        }
		
		return FALSE;
	}
	
	public function get_by_username($username){
		$identity_column = $this->config->item('identity');
	    $users_table     = $this->tables['users'];
	    
		$this->db->select($identity_column);
		$this->db->where('username', $username);
		$query = $this->db->get($users_table);
		
		$result = $query->row();
		
		if ($query->num_rows() == 1)
        {
        	return $this->profile($result->{$identity_column});
        }
		
		return FALSE;
	}
}
